/* --------------------------------------------------------- * * __________ D E L T A S C R I P T * * (_________() * * / === / - A fast, dynamic scripting language * * | == | - Version 4.13.11.0 * * / === / - Developed by Adam R. Nelson * * | = = | - 2011-2013 * * / === / - Distributed under GNU LGPL v3 * * (________() - http://github.com/ar-nelson/deltascript * * * * --------------------------------------------------------- */ package com.sector91.delta.script.runner; import java.io.IOException; import java.nio.charset.Charset; import jline.console.ConsoleReader; import jline.console.UserInterruptException; import org.fusesource.jansi.Ansi.Attribute; import org.fusesource.jansi.Ansi.Color; import org.fusesource.jansi.AnsiConsole; import org.fusesource.jansi.Ansi; import com.sector91.delta.script.DScriptContext; import com.sector91.delta.script.DScriptErr; import com.sector91.delta.script.DeltaScript; import com.sector91.delta.script.instrs.DSInstr; import com.sector91.delta.script.objects.DS_Blank; import com.sector91.delta.script.objects.DS_Boolean; import com.sector91.delta.script.objects.DS_Object; import com.sector91.delta.script.objects.DS_Scope; import com.sector91.delta.script.objects.DS_String; import com.sector91.delta.script.parser.DScriptLexer; import com.sector91.delta.script.parser.DScriptLexerException; import com.sector91.delta.script.parser.DScriptParser; import com.sector91.delta.script.parser.DScriptParserException; import com.sector91.delta.script.parser.LexToken; public class DeltaScriptFancyInterpreter implements Runnable { private static final String UNICODE_PROMPT = " \u03b4 > ", ASCII_PROMPT = " ds> ", BLOCK_PROMPT = "...> ", RESULT_PROMPT = "out) ", ERROR_PROMPT = "err! ", SCRIPT_NAME = "[Interpreter Script]"; private final boolean unicode; private boolean running; private String line = null; private final ConsoleReader reader; private final DScriptContext context; private final DS_Scope scope; public DeltaScriptFancyInterpreter(DScriptContext context, DS_Scope scope) throws IOException { this.reader = new ConsoleReader(); this.reader.setExpandEvents(false); this.reader.setBellEnabled(false); this.reader.setHandleUserInterrupt(true); this.context = context; this.scope = scope; this.unicode = Charset.defaultCharset().contains( Charset.forName("UTF-8")); } public static void main(String[] args) throws IOException { final DScriptContext context = new DScriptContext(); new DeltaScriptFancyInterpreter(context, context.createScope()).run(); } public synchronized void run() { running = true; try { AnsiConsole.systemInstall(); writeBanner(); while (running) { try { final DSInstr instr = readInput(); if (instr != null) { final DS_Object result = DeltaScript.exec(instr, scope, context); writeResult(result); } } catch (DScriptParserException ex) {writeParseError(line, ex);} catch (DScriptErr err) {writeDeltaScriptError(line, err);} catch (UserInterruptException ex) { AnsiConsole.out.println("Goodbye!"); System.exit(0); } catch (Exception ex) {writeJavaError(ex);} } } catch (IOException ex) { ex.printStackTrace(); } } private void writeBanner() throws IOException { AnsiConsole.out.println(Ansi.ansi() .fg(Color.CYAN).a(" __________ ").fg(Color.DEFAULT).a(Attribute.INTENSITY_BOLD) .a(" D E L T A S C R I P T").reset().newline() .fg(Color.CYAN).a(" (_________()").newline() .fg(Color.CYAN).a(" / === / ").reset().a(" - Version ").a(DeltaScript.VERSION).newline() .fg(Color.CYAN).a(" | == | ").reset().a(" - Developed by ").a(DeltaScript.AUTHOR).newline() .fg(Color.CYAN).a(" / === / ").reset().a(" - ").a(DeltaScript.WEBSITE).newline() .fg(Color.CYAN).a(" | = = | ").reset() .a(" - Distributed under the GNU LGPL v3").newline() .fg(Color.CYAN).a(" / === / ").newline() .fg(Color.CYAN).a(" (________() ").fg(Color.RED).a("Press CTRL-C to exit.") .reset().newline()); } private DSInstr readInput() throws IOException, DScriptParserException { line = reader.readLine(Ansi.ansi() .fg(Color.YELLOW).a(unicode? UNICODE_PROMPT:ASCII_PROMPT).reset() .toString()); final DScriptParser parser = new DScriptParser(context); DScriptLexer lexer = new DScriptLexer(line); LexToken token = null; while (lexer.hasNext()) token = lexer.next(); if (token == null) return null; try { token.value(); while (lexer.topUnclosedToken() != null) { line += "\n" + reader.readLine(Ansi.ansi() .fg(Color.GREEN).a(BLOCK_PROMPT).reset() .toString()); lexer = new DScriptLexer(line); token = null; while (lexer.hasNext()) token = lexer.next(); if (token != null) token.value(); } return parser.compile(line, SCRIPT_NAME); } catch (DScriptLexerException ex) { // Compile so that a parser exception will be thrown. parser.compile(line, SCRIPT_NAME); } return null; } private void writeResult(DS_Object result) throws IOException { Color color = Color.CYAN; String str = String.valueOf(result); if (result instanceof DS_String) { color = Color.GREEN; str = "\"" + str.replace("\\","\\\\").replace("\"","\\\"") + "\""; } else if (result instanceof DS_Boolean || result == DS_Blank.BLANK) color = Color.MAGENTA; // TODO: Special formatting for arrays, lists, maps... AnsiConsole.out.println(Ansi.ansi() .fg(Color.BLUE).a(RESULT_PROMPT).fg(color).a(str).reset()); } private void writeParseError(String source, DScriptParserException error) { AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).a("== Parse Error ==").reset()); AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).reset().a(error.getMessage())); for (String line : error.getLocatorText(source).split("\r?\n")) AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).reset().a(line)); } private void writeDeltaScriptError(String source, DScriptErr error) { AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).a("== DeltaScript Error ==").reset()); AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).reset().a(error.getMessage())); for (String line : error.getLocatorText(SCRIPT_NAME, source).split("\r?\n")) AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).reset().a(line)); } private void writeJavaError(Throwable error) { AnsiConsole.out.println(Ansi.ansi() .fg(Color.RED).a(ERROR_PROMPT).a("== Java Error ==").reset()); error.printStackTrace(AnsiConsole.out); } }